import requests
from xml.etree import ElementTree as ET
import chardet
import json
from typing import List
from ..log import logger
from ..lib.webservice import WebService
from ..lib.common import get_json_node_value_by_path, get_xml_etree_value
from ..globals import g


def http(step):
    data: dict = step['data']
    expect: dict = step['expected']
    output: dict = step['output']

    request_url = data.get('请求地址')
    request_method:str = data.get('请求方法')
    request_headers = data.get('请求头')
    request_body: str = data.get('请求体')
    request_charset: str = data.get('请求报文编码类型', 'utf-8')
    request_json = data.get('请求json')
    request_cookies = data.get('cookies')
    request_timeout = data.get('timeout')

    try:
        method = getattr(requests, request_method.lower())
    except AttributeError:
        logger.error(f'错误的请求方法"{request_method}"，请求方法应如：get、post、put、patch、delete')
        raise AssertionError(f'错误的请求方法"{request_method}"，请重新填写！')

    params = {}
    params['headers'] = {}
    if request_headers:
        params['headers'] = json.loads(request_headers)
    if request_cookies:
        params['headers']['cookies'] = request_cookies
    if request_timeout:
        params['timeout'] = int(request_timeout)
    if request_json:
        params['json'] = request_json
    if request_body:
        params['data'] = request_body.encode(request_charset)

    res = method(request_url, **params)
    res_content = res.content
    coding = chardet.detect(res_content)
    res_text = res_content.decode(encoding=coding['encoding'])
    logger.info(f'返回报文：{res_text}')

    if expect or output:
        try:
            res_json = json.loads(res_text)
        except:
                res_json = None
        try:
            res_xml = ET.fromstring(res_text)
        except:
            res_xml = None

    for node_path, expect_value in expect.items():
        if node_path == '全量校验':
            assert expect_value == res_text, f'预期结果[全量校验]校验失败，预期值:"{expect_value}"'
        elif node_path == '包含校验':
            assert expect_value in res_text, f'预期结果[包含校验]校验失败，预期值包含值:"{expect_value}"'
        elif res_json:
            real_v = get_json_node_value_by_path(res_json, path=node_path, join='.')
            assert expect_value == real_v, f'预期结果[json]校验失败，预期值:"{expect_value}" 实际值:"{real_v}"'
        elif res_xml:
            real_v = get_xml_etree_value(res_xml, node_path)
            assert real_v is not None, f'未在返回报文中找到节点元素: "{node_path}"'
            assert expect_value == real_v, f'预期结果[xml]校验失败，预期值:"{expect_value}" 实际值:"{real_v}"'

    for var_name, node_path in output.items():
        v = get_xml_etree_value(res_xml, node_path)
        assert v is not None, f'未在返回报文中找到节点元素: "{node_path}"'
        g.update_var(key=var_name, value=v)


def webservice(step: dict):
    """
    通过requests模拟webservice

    测试数据:
        请求url: 请求URL；
        请求报文: 请求报文；

    输出数据：
        nodePath: 节点路径；

    预期结果：
        nodePath: 节点路径；
    """
    data: dict = step['data']
    output: dict = step['output']
    expected: dict = step['expected']

    url = data['请求url']
    msg = data['请求报文']

    ret_msg = WebService(url, msg).send_request()
    logger.info(f'返回报文: {ret_msg}')
    dom = ET.fromstring(ret_msg)
    for node_path, value in expected.items():
        real = get_xml_etree_value(dom, node_path)
        assert real is not None, f'未在返回报文中找到节点元素: "{node_path}"'
        if real != value:
            raise AssertionError(f'预期项:"{node_path}"，预期值:"{value}"，当前值:"{real}"，预期结果校验失败！')

    for var_name, node_path in output.items():
        v = get_xml_etree_value(dom, node_path)
        assert v is not None, f'未在返回报文中找到节点元素: "{node_path}"'
        g.update_var(key=var_name, value=v)


